import {
    workspace,
} from "vscode";

import * as request from "request";
import { Api, Gist, GistFile } from "./api";


export default class Github implements Api {
    url: string;
    constructor() {
        this.url = "https://api.github.com";
    }

    public getToken(): string {
        return workspace.getConfiguration("gist").get("githubToken") || "";
    }

    public create(gist: Gist): Promise<void> {
        return new Promise((resolve, reject) => {
            request.post(`${ this.url }/gists`, {
                body: {
                    files: gist.files,
                    public: gist.public,
                    description: gist.description,
                },
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 201) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve();
                }
            });
        });
    }

    public delete(id: string): Promise<void> {
        return new Promise((resolve, reject) => {
            request.delete(`${ this.url }/gists/${ id }`, {
                body: {
                    id,
                    access_token: this.getToken(),
                },
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 204) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve();
                }
            });
        });
    }

    public deleteFile(id: string, fileName: string): Promise<void> {
        return new Promise((resolve, reject) => {
            request.patch(`${ this.url }/gists/${ id }`, {
                body: {
                    files: {
                        [fileName]: null,
                    },
                },
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve();
                }
            });
        });
    }

    public getList(limit: number, page: number): Promise<Gist[]> {
        return new Promise((resolve, reject) => {
            request.get(`${ this.url }/gists?page=${ page }&per_page=${ limit }`, {
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve(res.body.map((item: any): Gist => {
                        return {
                            id: item.id,
                            files: item.files,
                            public: item.public,
                            description: item.description,
                        };
                    }));
                }
            });
        });
    }

    public edit(gist: Gist): Promise<void> {
        return new Promise((resolve, reject) => {
            request.patch(`${ this.url }/gists/${ gist.id }`, {
                body: {
                    files: gist.files,
                    description: gist.description,
                },
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve();
                }
            });
        });
    }

    public getPublicList(limit: number, page: number): Promise<Gist[]> {
        return new Promise((resolve, reject) => {
            request.get(`${ this.url }/gists?page=${ page }&per_page=${ limit }`, {
                headers: {
                    "User-Agent": "vscode-gist"
                },
                json: true,
            }, async (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve(res.body.map((item: any): Gist => {
                        return {
                            id: item.id,
                            files: item.files,
                            public: item.public,
                            description: item.description,
                        };
                    }));
                }
            });
        });
    }

    public getSingle(id: string): Promise<Gist> {
        return new Promise((resolve, reject) => {
            request.get(`${ this.url }/gists/${ id }`, {
                headers: {
                    "User-Agent": "vscode-gist",
                    "authorization": `token ${ this.getToken() }`
                },
                json: true,
            }, (err, res) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(typeof res.body === "string" ? res.body : JSON.stringify(res.body));
                } else {
                    resolve();
                }
            });
        });
    }

    public getContent(gistFile: GistFile): Promise<string> {
        return new Promise((resovle, reject) => {
            request.get(gistFile.raw_url || "", (err: any, res: request.Response) => {
                if (err) {
                    reject(err.message);
                } else if (res.statusCode !== 200) {
                    reject(res.body);
                } else {
                    gistFile.content = res.body;
                    resovle(res.body);
                }
            });
        });
    }
}